<?php

/**
 * 路由
 * 
 * 使用方式参见 App\route.php 文件
 */
class Route {

    /**
     * 路由表，保存所有路由数据
     *
     * @var array
     */
    private static $_route = array();

    /**
     * 防止类实例化
     */
    private function __construct() {
        
    }

    /**
     * 防止对象被复制
     */
    private function __clone() {
        
    }

    /**
     * 判断当前url是否与指定前导url匹配
     * 可以用来隔离路由，减少路由匹配的次数，提升性能
     * 
     * @param string $prefix_uri
     * @return boolean
     */
    static public function prematch($prefix_uri) {

        $request = Request::getInstance();

        $request_path = $request->requestPath();

        return stripos($request_path, $prefix_uri) === 0;
    }

    /**
     * 路由缓存
     * 
     * @param string $name 缓存名称
     * @param array $routes 路由数据，不传该参数为读取，传入该参数为保存
     * @return mixed
     */
    static public function cache($name, $routes = null) {

        $route_file = DATA_PATH . '/Route/' . $name . '.php';

        if ($routes === null) {

            if (is_file($route_file)) {


                $routes = include($route_file);
                
                if (!is_array($routes)) {
                    return array();
                }

                return $routes;
            } else {
                return array();
            }
        } else {

            if (!file_exists(dirname($route_file))) {
                mkdir(dirname($route_file), 0775, true);
            }

            if (is_array($routes)) {

                return file_put_contents($route_file, "<?php \n\n return " . var_export($routes, true) . ';');
            } else {
                return false;
            }
        }
    }

    /**
     * 设置路由
     *
     * @param array $routes 路由数据
     */
    static public function set($routes = array()) {

        if (!$routes) {
            return;
        }

        if (is_array($routes) && isset($routes['uri'])) {

            if (!isset($routes['name']) || !$routes['name']) {
                $routes['name'] = uniqid();
            }
            self::$_route[$routes['name']] = $routes;
        } else {

            foreach ($routes as $route) {

                if (!isset($route['name']) || !$route['name']) {
                    $route['name'] = uniqid();
                }
                self::$_route[$route['name']] = $route;
            }
        }
    }

    /**
     * 路由分组，返回的分组数据需要使用set方法写入路由表
     * 
     * @param array $prefix 路由分组前缀，对应的数据会被拼接到路由前端
     * 
     * @param array $routes 路由数据，路由数据的数据项也可以是group方法的返回结果
     * 
     * @return array 路由数据
     */
    static public function group($prefix, $routes) {

        $rs = array();

        foreach ($routes as $route) {

            if (is_array($route) && isset($route['uri'])) {

                if (isset($prefix['name']) && $prefix['name'] != '') {
                    if (isset($route['name']) && $route['name'] != '') {
                        $route['name'] = $prefix['name'] . '/' . $route['name'];
                    } else {
                        $route['name'] = $prefix['name'];
                    }
                }

                if (isset($prefix['uri']) && $prefix['uri'] != '') {
                    if (isset($route['uri']) && $route['uri'] != '') {
                        $route['uri'] = $prefix['uri'] . $route['uri'];
                    } else {
                        $route['uri'] = $prefix['uri'];
                    }
                }

                if (!isset($route['module']) || $route['module'] == '') {
                    if ($prefix['module']) {
                        $route['module'] = $prefix['module'];
                    }
                }

                if (isset($prefix['controller']) && $prefix['controller'] != '') {
                    if (isset($route['controller']) && $route['controller'] != '') {
                        $route['controller'] = $prefix['controller'] . '\\' . $route['controller'];
                    } else {
                        $route['controller'] = $prefix['controller'];
                    }
                }

                $rs[] = $route;
            } else {

                $rs = array_merge($rs, self::group($prefix, $route));
            }
        }

        return $rs;
    }

    /**
     * 获取路由配置
     *
     * @param string $name 名称,如果名称为空则返回所有路由配置
     * @return array 路由数据
     */
    static public function get($name = '') {
        return $name == '' ? self::$_route : (isset(self::$_route[$name]) ? self::$_route[$name] : false);
    }

    /**
     * 返回匹配 URI 的路路由配置,这个方法框架会调用
     *
     * @param str $uri
     */
    static public function matches($uri) {
        // 得到所有设置的路由URI
        $regexUri = array();
        foreach (self::$_route as $name => $param) {
            // 如果没有设置 bind 字段
            if (!isset($param['bind'])) {
                $regexUri[$name] = $param['uri'];
                continue;
            }
            // 将 uri 和 bind 合并
            $search = $replace = array();
            foreach ($param['bind'] as $key => $value) {
                $search[] = '<' . $key . '>';
                $replace[] = $value;
            }
            $regexUri[$name] = str_replace($search, $replace, $param['uri']);
        }

        // 遍历 URI 匹配，找到第一个即认为找到了
        foreach ($regexUri as $name => $regUri) {
            // 合并成正则表达式
            $regUri = '/' . str_replace('/', "\\/", $regUri) . '/';

            // 匹配
            $bool = preg_match($regUri, $uri, $match);

            
            // 如果没有找到则直接下一个继续
            if (!$bool || $match[0] !== $uri) {
                continue;
            }
            
            // 如果找到了则就返回找到的第一个配置
            $route = self::$_route[$name];

            // 如果没有搜索到子项则直接返回
            if (count($match) == 1) {
                return $route;
            }

            // 搜索到了则要 设置 Request 的 param()
            $param = array();
            $i = 0;
            $keyArr = array_keys($route['bind']);
            foreach ($keyArr as $key) {
                ++$i;
                $param[$key] = isset($match[$i]) ? $match[$i] : '';
            }

            Request::getInstance()->setParam($param);

            // 返回匹配到的route
            return $route;
        }
        return array();
    }

    /**
     * 判断是否使用了路由,这个方法框架会调用
     *
     * @return boolean
     */
    static public function isUseRoute() {
        return self::$_route ? true : false;
    }

}
